元類定義如下:
class MyMeta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
# uses attribute a,b,c,d
a = namespace["a"]
b = namespace["b"]
c = namespace["c"]
d = namespace["d"]
...
return super().__new__(metacls, name, bases, namespace, **kwargs)
這個元類使用屬性a, b, c, d。現在可以使用以下方式創建類metaclass:
class A(metaclass=MyMeta):
a = "etc/dev"
b = 2
c = "c"
d = "d"
class B(metaclass=MyMeta):
a = "etc/dev/null"
b = 2
c = "c"
d = "d"
a每個類的屬性都是可變的。我想提取基類中的常量屬性以避免重復:
class BaseClass:
b = 2
c = "c"
d = "d"
并使用元類創建類:
class A(BaseClass, metaclass=MyMeta):
a = "/etc/dev"
class B(BaseClass, metaclass=MyMeta):
a = "/etc/dev/null"
元類抱怨它無法b從父類中找到屬性。
test_mode = namespace["b"]
KeyError: 'b'
有沒有辦法將屬性從父級傳遞給子元類?
約束:無法更新MyMeta元類,因為它是從現有庫中借用/匯入的。
uj5u.com熱心網友回復:
您可以通過使元類__new__()方法也檢查正在定義的類的所有基類的名稱空間來做到這一點。這是一種方法。請注意,它會過濾掉名稱空間中具有 dunder 識別符號的屬性。
由于您無法更改您“借用”的元類,因此從它派生了一個自定義類。我早期答案的這個修訂版還使用collection.ChainMap該類來考慮所有命名空間,而無需實際將它們全部組合起來。
from collections import ChainMap
import re
class BorrowedMeta(type):
def __new__(metacls, name, bases, namespace, **kwargs):
# uses attribute a,b,c,d
a = namespace["a"]
b = namespace["b"]
c = namespace["c"]
d = namespace["d"]
...
return super().__new__(metacls, name, bases, namespace, **kwargs)
def is_dunder(name):
"""Determine if name is a Python dunder identifier."""
return re.match(r'^__[^\d\W]\w*\Z__$', name, re.UNICODE)
class MyMeta(BorrowedMeta):
def __new__(metacls, name, bases, namespace, **kwargs):
chainmap = ChainMap(*[namespace]
[{k: v for (k, v) in vars(base).items() if not(is_dunder(k))}
for base in bases])
return super().__new__(metacls, name, bases, {**chainmap}, **kwargs)
class BaseClass:
b = 2
c = "c"
d = "d"
class A(BaseClass, metaclass=MyMeta):
a = "/etc/dev"
class B(BaseClass, metaclass=MyMeta):
a = "/etc/dev/null"
from pprint import pprint
pprint(vars(A))
print()
pprint(vars(B))
輸出:
mappingproxy({'__doc__': None,
'__module__': '__main__',
'a': '/etc/dev',
'b': 2,
'c': 'c',
'd': 'd'})
mappingproxy({'__doc__': None,
'__module__': '__main__',
'a': '/etc/dev/null',
'b': 2,
'c': 'c',
'd': 'd'})
uj5u.com熱心網友回復:
不,如果不改變元類的行為,你就不能做你想做的事。
問題是正在查找的namespace引數僅包含在陳述句中為新類定義的值。它不包含任何繼承的東西,因為類和它的基礎還沒有組合(這就是它在實作的底部呼叫時所做的事情,在它使用//變數完成它的事情之后)。MyMeta.__new__classMyMeta.__new__super().__new__abc
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/424207.html
上一篇:如何從繼承的類中獲取新的變數值?
下一篇:如何要求子類方法呼叫父類方法?
