问题描述
我有一个带有私有常量 _BAR = object()
的类。
在子类中,在方法之外(无法访问 self
),我想引用 _BAR
。
这是一个人为的例子:
class Foo:
_BAR = object()
def __init__(self,bar: object = _BAR):
...
class DFoo(Foo):
"""Child class where I want to access private class variable from parent."""
def __init__(self,baz: object = super()._BAR):
super().__init__(baz)
不幸的是,这不起作用。一个错误:RuntimeError: super(): no arguments
解决方法是使用 Foo._BAR
,我想知道是否可以使用 super
来解决这个问题。
解决方法
在 import {
GetStaticPropsContext,GetStaticPropsResult,GetStaticPathsContext,InferGetStaticPropsType
} from 'next';
import { initializeApollo,addApolloState } from '@/lib/apollo';
import {
DynamicNavDocument,DynamicNavQueryVariables,DynamicNavQuery,WordpressMenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';
import { AppLayout } from '@/components/Layout';
import { useRouter } from 'next/router';
import { Container,Fallback } from '@/components/UI';
import useSWR from 'swr';
import { fetcherGallery } from '@/lib/swr-fetcher';
import { Gallery } from '@/types/booksy/media';
import { Configuration,Fetcher } from 'swr/dist/types';
import {
getLatestBooksyPhotos,getBooksyPhotoById
} from '@/lib/booksy';
import Image,{ ImageLoaderProps } from 'next/image';
import { parseUrl } from '@/lib/helpers';
export async function getStaticPaths({
locales
}: GetStaticPathsContext): Promise<{
paths: string[];
fallback: false;
}> {
const data: Response = await getLatestBooksyPhotos();
const pathsData: Gallery = await data.json();
return {
paths: locales
? locales.reduce<string[]>((arr,locale) => {
pathsData.images.forEach(imageId => {
arr.push(`/${locale}/gallery/${imageId.image_id}`);
});
return arr;
},[])
: pathsData?.images.map(
imageId => `/gallery/${imageId.image_id}`
),fallback: false
};
}
export async function getStaticProps<P>(
ctx: GetStaticPropsContext
): Promise<
GetStaticPropsResult<
P & {
Header: DynamicNavQuery['Header'];
Footer: DynamicNavQuery['Footer'];
initDataImage: Partial<
Configuration<Gallery,any,Fetcher<Gallery>>
>;
id: string;
}
>
> {
const apolloClient = initializeApollo({
headers: ctx.params ?? {}
});
await apolloClient.query<
DynamicNavQuery,DynamicNavQueryVariables
>({
notifyOnNetworkStatusChange: true,fetchPolicy: 'cache-first',query: DynamicNavDocument,variables: {
idHead: 'Header',idTypeHead: WordpressMenuNodeIdTypeEnum.NAME,idTypeFoot: WordpressMenuNodeIdTypeEnum.NAME,idFoot: 'Footer'
}
});
const id = ctx?.params ? (ctx.params.id as string) : '21177790';
const initDataGallery = await getBooksyPhotoById(id);
const initDataImage: Gallery = await initDataGallery.json();
return addApolloState(apolloClient,{
props: {
initDataImage,id
},revalidate: 600
});
}
export default function GalleryById<
T extends typeof getStaticProps
>({
Header,Footer,initDataImage,id
}: InferGetStaticPropsType<T>) {
const router = useRouter();
const parsedId = router.query
? (router.query.id as string)
: '';
const { data } = useSWR<Gallery>(
`/api/booksy-image-by-id/?category=biz_photo&image_id=${
id ? id : parsedId
}`,fetcherGallery,initDataImage
);
const booksyImageLoader = ({
src,width,quality
}: ImageLoaderProps) => {
return `${src}?w=${width}&q=${quality || 75}`;
};
const targetThumbnail = data?.images[0].thumbnails['640,0-hr']
.url
? data.images[0].thumbnails['640,0-hr'].url
: data?.images[0].image
? data.images[0].image
: '';
const thumbnailDecoded = decodeURI(targetThumbnail ?? '');
const fragmentThumbnailURI = parseUrl(thumbnailDecoded ?? '');
const thumbnailReconstructed =
`${fragmentThumbnailURI?.baseUrl.concat(
fragmentThumbnailURI.pathname
)}
` ?? '';
return (
<>
{router.isFallback ? (
<Fallback />
) : (
<AppLayout
Header={Header}
Footer={Footer}
title={`${data?.images[0].image_id ?? parsedId}`}
>
<Container
clean
className='my-16 max-w-5xl mx-auto block rounded-xl shadow-cardHover'
>
{data && data.images ? (
<Image
className='rounded-xl object-cover'
src={
thumbnailReconstructed !== ''
? thumbnailReconstructed
: '/doge-404.jpg'
}
loader={booksyImageLoader}
width='1280'
height='1294'
priority
quality={100}
layout='responsive'
/>
) : (
<Fallback />
)}
</Container>
</AppLayout>
)}
</>
);
}
中,您不能在不引用 DFoo
的情况下引用 Foo._BAR
。 Python 变量在局部、封闭、全局和内置作用域中搜索(按此顺序,这是所谓的 LEGB 规则)并且 Foo
不存在于其中任何一个。
让我们忽略显式 _BAR
。
此外,它会被继承:Foo._BAR
将首先在 DFoo._BAR
中查找,如果找不到,则在 DFoo
中查找。
还有什么其他方法可以获取 Foo
引用? Foo
是 Foo
的基类。我们可以使用这种关系吗?是和否。执行时是,定义时否。
问题是在定义 DFoo
时,它还不存在。我们没有开始遵循继承链的起点。这排除了 DFoo
行和类属性 DFoo
中的间接引用(Foo
-> def method(self,....):
)。
可以使用类装饰器来解决此限制。定义类然后修改:
_DBAR = _BAR
使用元类可以达到类似的效果。
获取对 def deco(cls):
cls._BAR = cls.__mro__[1]._BAR * 2 # __mro__[0] is the class itself
return cls
class Foo:
_BAR = 10
@deco
class DFoo(Foo):
pass
print(Foo._BAR,DFoo._BAR) # 10 20
的引用的最后一个选项是在执行时。我们有对象Foo
,它的类型是self
,它的父类型是DFoo
,并且存在Foo
。众所周知的 _BAR
是获取父级的快捷方式。
为简单起见,我只假设了一个基类。如果有多个基类,super()
只返回其中之一。示例类装饰器也做同样的事情。要了解多个碱基如何排序为一个序列,请参阅 MRO 的工作原理(方法解析顺序)。
我的最后一个想法是,我无法想出一个需要问题中的访问权限的用例。
,简短的回答:你不能!
我不会详细介绍 "super",但让我们看看如何调用 super:
1- 没有参数,正如文档所说:
零参数形式仅在类定义中有效,因为 编译器填写必要的详细信息以正确检索 正在定义的类,以及访问当前实例 普通方法。
(除非被调用,否则函数/方法的主体不会被执行,所以如果 DFoo
尚不存在也没有问题)
2- 有两个论点,上面提到的那些必要细节是什么?一个“类型”和一个“实例”:
我们不能在这里传递 DFoo
的“实例”和“类型”。第一个是因为它不在方法内部,所以我们无法访问 instance(self)。第二个是 DFoo
本身。当 DFoo
类的主体被执行时,没有对 DFoo
的引用,它还不存在。类的主体在作为字典的命名空间内执行。 之后,使用该填充的字典创建了一个 type
类型的新实例,此处名为 DFoo
,并将其添加到全局命名空间中。这就是 class
关键字在简单形式中的大致作用。
3-另外两个都是类型的参数:
如果第二个参数是类型,则 issubclass(type2,type) 必须是 真的
上面提到的关于访问 DFoo
的相同原因。
4- 还有另一种形式可以用一个参数调用 super,它是一个单一的“类型”:
如果省略第二个参数,则返回的超级对象为 未绑定。
再次访问上述 DFoo
类型的相同原因,没有任何改变。只是为了记录而添加。这些是我们调用 super
的方式。