[英]Detect re-declaration of Python class variables
假設我有一個 Python 類,如下所示:
class Foo:
one = 'some value'
two = 'some other value'
# ... and so on ...
twenty = 'blah blah'
one = 'updated value' # OH NOEEESSS :o
我想檢測(並可能阻止)在類主體中重新聲明Foo.one
。
有沒有辦法在運行時以編程方式甚至通過 lint 規則檢測到這一點?
如果有幫助,我的用例會更具體一些。 我想避免重復使用Flask SQLAlchemy模型的列名,我有很長的列列表,並且在嘗試添加新列時我冒着重新使用舊列名的風險。 例如:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class UserModel(db.Model):
""" A sample user model """
__tablename__ = 'user'
name = db.Column(db.String)
is_dead = db.Column(db.Boolean)
# ... and so on ...
name = db.Column(db.String) # Detect/prevent re-declaration of 'name'
我設法在運行時使用元類、特殊字典並通過覆蓋元類的__prepare__
方法解決了我的特定用例:
from sqlalchemy.sql.schema import Column
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class NoColumnReassignmentDict(dict):
def __setitem__(self, key, value):
if key in self and isinstance(self[key], Column):
raise Exception(f'Cannot re-assign column <{key}>')
return super().__setitem__(key, value)
class MetaBaseModel(type(db.Model)):
@classmethod
def __prepare__(cls, *args, **kwargs):
return NoColumnReassignmentDict()
class UserModel(db.Model, metaclass=MetaBaseModel):
""" A sample user model """
__tablename__ = 'user'
user_id = db.Column(db.String, nullable=False, primary_key=True)
name = db.Column(db.String)
is_dead = db.Column(db.Boolean)
# ... and so on ...
name = db.Column(db.String) # Raises: 'Exception: Cannot re-assign column <name>'
我想這也可以擴展到通用用例。
PS: 這是一個很好的參考!
我不完全確定這會起作用; 我不記得db.Model
使用了可能會干擾這個的元類。 但是,您可以使用已預先篩選重復項的屬性字典直接調用type
,而不是使用class
語句。
def checkForDuplicateFields(fields):
seen = set()
for k in fields:
if k in seen:
raise ValueError(f"Duplicate key {k} found")
seen.add(k)
fields = [
('name', db.Column(db.String)),
...
]
checkForDuplicateFields(fields)
UserModel = type('UserModel', (db.Model,), dict(fields))
(如果db.Model
確實使用了其他一些元類,例如DBMeta
,那么您將調用它而不是type
:
UserModel = DBMeta('UserModel', (db.Model,) dict(fields))
)
(我不確定這是什至自定義元類可以處理的事情。 class
語句的工作方式,主體中分配的名稱被收集到一個dict
並作為參數傳遞給元類。您需要class
語句來在元類被調用之前,使用一種特殊的dict
拒絕重復賦值(或者至少是一個 multi dict,它在標准 Python 中不存在),我不知道是否有任何鈎子允許這樣做。)
如何檢查屬性是否首先設置?
class Foo:
def __init__(self):
self.one = 'some value'
self.two = 'some other value'
# ... and so on ...
self.twenty = 'blah blah'
if not hasattr(self, 'one'):
self.one = 'updated value' # Aww yea
如果變量是 config 的形式或者它們的字符串名稱是已知的:
class Foo:
def __init__(self):
self.one = 'some value'
self.two = 'some other value'
# ... and so on ...
self.twenty = 'blah blah'
if not hasattr(self, 'one'):
setattr(self, 'one', 'updated value') # Aww yea 2
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.